package cn.cj.erp.modules.system.controller;

import cn.cj.erp.bo.system.SysNoticeBo;
import cn.cj.erp.bo.system.SysNoticeUserReadBo;
import cn.cj.erp.common.utils.id.IdGenerator;
import cn.cj.erp.modules.common.controller.AbstractController;
import cn.cj.erp.service.system.SysNoticeService;
import cn.cj.erp.service.system.SysNoticeUserReadService;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.cj.erp.common.security.annotation.Log;
import cn.cj.erp.common.enums.LogBusinessTypeEnum;
import cn.cj.erp.common.Page;
import cn.cj.erp.common.http.Result;
import cn.cj.erp.common.security.security.user.LoginUser;
import cn.cj.erp.common.security.security.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 通知公告表
 * @author chenjian
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/system/notice")
public class SysNoticeController extends AbstractController {
    @Resource
    private SysNoticeService sysNoticeService;
    @Resource
    private SysNoticeUserReadService sysNoticeUserReadService;
    
    /**
    * 列表
    */
    @PostMapping("/list")
    @PreAuthorize("@ss.hasPerm('system:notice:list')")
    public Result<Page<SysNoticeBo>> list(@RequestBody SysNoticeBo params) {
        return Result.query(sysNoticeService.queryPage(params));
    }

    /**
    * 获取通知公告
    */
    @GetMapping("/info/{id}")
    @PreAuthorize("@ss.hasPerm('system:notice:query')")
    public Result<SysNoticeBo> info(@PathVariable("id") Long id) {
        return Result.query(sysNoticeService.getById(id));
    }

    /**
    * 保存公告
    */
    @PostMapping("/save")
    @PreAuthorize("@ss.hasPerm('system:notice:add')")
    @Log(title = "通知公告表", businessType = LogBusinessTypeEnum.INSERT)
    public Result<Boolean> save(@Valid @RequestBody SysNoticeBo sysNoticeBo) {
        sysNoticeBo.setId(IdGenerator.generateId());
        return Result.save(sysNoticeService.save(sysNoticeBo));
    }

    /**
     * 修改
     */
    @PostMapping("/update")
    @PreAuthorize("@ss.hasPerm('system:notice:edit')")
    @Log(title = "通知公告表", businessType = LogBusinessTypeEnum.UPDATE)
    public Result<Boolean> update(@Valid @RequestBody SysNoticeBo sysNoticeBo) {
        return Result.update(sysNoticeService.updateById(sysNoticeBo));
    }

    /**
     * 删除
     */
    @PostMapping("/delete/{ids}")
    @PreAuthorize("@ss.hasPerm('system:notice:remove')")
    @Log(title = "通知公告表", businessType = LogBusinessTypeEnum.DELETE)
    public Result<Boolean> delete(@PathVariable("ids") Long[] ids) {
        return Result.remove(sysNoticeService.removeByIds(Arrays.asList(ids)));
    }

    /**
     * 获取个人公告阅读列表
     */
    @PostMapping("listUserNotice")
    public Result<Page<SysNoticeBo>> listUserNotice(@RequestBody SysNoticeBo params) {
        Assert.notNull(params, "查询参数不能为空");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        params.setUserId(loginUser.getUserId());
        Page<SysNoticeBo> page = sysNoticeService.queryPage(params);
        // 填充用户阅读对应字段
        fillUserRead(params.getUserId(), page.getList());
        return Result.query(page);
    }

    /**
     * 将通知公告标记为已读
     */
    @Log(title = "公告标记为已读", businessType = LogBusinessTypeEnum.UPDATE)
    @PostMapping("updateNoticeToRead/{noticeIds}")
    public Result<Boolean> updateNoticeToRead(@PathVariable Long[] noticeIds) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if(ArrayUtil.isEmpty(noticeIds)){
            return Result.ok();
        }
        return Result.update(sysNoticeService.setUserRead(loginUser.getUserId(), Arrays.asList(noticeIds)));
    }

    /**
     * 获取公告详细信息
     */
    @GetMapping(value = "getNoticeView/{noticeId}")
    public Result<SysNoticeBo> getNoticeView(@PathVariable Long noticeId) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysNoticeBo vo = sysNoticeService.getById(noticeId);
        sysNoticeService.setUserRead(loginUser.getUserId(), Collections.singletonList(noticeId));
        return Result.ok(vo);
    }

    // --------------------------------
    /**
     * 公告实体类，填充用户阅读相关字段
     * @param userId 用户ID
     * @param list 公告列表
     */
    private void fillUserRead(Long userId, List<SysNoticeBo> list) {
        if (CollectionUtil.isEmpty(list)) {
            // 列表为空则不进行处理
            return;
        }
        // 得到公告id列表
        List<Long> ids = list.stream()
                .map(SysNoticeBo::getId)
                .collect(Collectors.toList());
        // 获取用户的阅读列表
        List<SysNoticeUserReadBo> tmpList = sysNoticeUserReadService.listUserRead(userId, ids);
        // 转化用户阅读列表成map， key为公告id，value为用户阅读实体类
        Map<Long, SysNoticeUserReadBo> userReadMap = tmpList.stream().collect(Collectors.toMap(
                SysNoticeUserReadBo::getNoticeId,
                Function.identity(),
                (key1, key2) -> key1));
        // 开始填充数据
        for (SysNoticeBo record : list) {
            if (userReadMap.containsKey(record.getId())) {
                SysNoticeUserReadBo tmp = userReadMap.get(record.getId());
                record.setReadStatus(tmp.getReadStatus());
                record.setSysNoticeUserRead(tmp);
            }
        }
    }
}
